package main
import (
	"fmt"
	"net/http"
	"encoding/json"
	"log"
	"os"
	"strings"
	"strconv"
	"bufio"
)


type DynamicInfo struct {
	Number int `json:"number"`
}

type SignInfo struct {
	Id string `json:"id"`
	Username string `json:"username"`
	Status int `json:"status"`
	Errer string `json:"errer"`
	Password string `json:"password"`
}

func ReadDynamicInfo() DynamicInfo {
	file, err := os.Open("dynamic/info.json")
	if err != nil {
		log.Fatal("Read file: ", err)
	} else {
		defer file.Close()
		info := DynamicInfo{}
		decoder := json.NewDecoder(file)
		err := decoder.Decode(&info)
		if err != nil {
			log.Fatal("Load json: ", err)
		} else {
			return info
		}
	}
	return DynamicInfo{}
}

func WriteDynamicInfo(InfoStruct DynamicInfo) {
	Info := InfoStruct

    file, err := os.Create("dynamic/info.json")
    if err != nil {
        log.Fatal("Write file: ", err)
    } else {
		defer file.Close()
		encoder := json.NewEncoder(file)
		err := encoder.Encode(Info)
		if err != nil {
			log.Fatal("Dump json: ", err)
		}
	}
}

func ReadSignInfo(Path string) SignInfo {
	file, err := os.Open(Path)
	if err != nil {
		log.Fatal("Read file: ", err)
	} else {
		defer file.Close()
		info := SignInfo{}
		decoder := json.NewDecoder(file)
		err := decoder.Decode(&info)
		if err != nil {
			log.Fatal("Load json: ", err)
		} else {
			return info
		}
	}
	return SignInfo{}
}

func WriteSignInfo(InfoStruct SignInfo, Path string) {
	Info := InfoStruct

    file, err := os.Create(Path)
    if err != nil {
        log.Fatal("Write file: ", err)
    } else {
		defer file.Close()
		encoder := json.NewEncoder(file)
		err := encoder.Encode(Info)
		if err != nil {
			log.Fatal("Dump json: ", err)
		}
	return
	}
}

func LoadSignInfo(InfoStruct SignInfo) string {
	data, err := json.Marshal(InfoStruct)
	if err != nil {
		log.Fatal("Load json: ", err)
	} else {
		return string(data)
	}
	return ""
}

func Signin(Id, Password string) string {
	filePath := "client/"+Id+".json"
	fileInfo, err := os.Stat(filePath)

	if fileInfo != nil && err == nil {
		info := ReadSignInfo(filePath)
		truePassword := info.Password
		if truePassword == Password {
			Username := info.Username
			return LoadSignInfo(SignInfo{Id: Id, Username: Username, Status: 1, Password: Password})
		} else {
			return LoadSignInfo(SignInfo{Status: 0, Errer: "Password is wrong"})
		}
	} else if os.IsNotExist(err) {
		return LoadSignInfo(SignInfo{Status: 0, Errer: "Id is not exist"})
	}
	return ""
}

func Signup(Username, Password string) string {
	if len(Password) > 8 && len(Password) > 16 && strings.Contains(Username, " "){
		return LoadSignInfo(SignInfo{Status: 0, Errer: "Password or username is not allowed"})
	} else {
		number := ReadDynamicInfo().Number + 1
		Id := strconv.Itoa(number)
		filePath := "client/"+Id+".json"
		WriteDynamicInfo(DynamicInfo{Number: number})
		WriteSignInfo(SignInfo{Id: Id, Username: Username, Password: Password}, filePath)
		err := os.Mkdir("service/"+Id, 0777)
		if err != nil {
			log.Fatal("Create dir: ", err)
		}
		return LoadSignInfo(SignInfo{Id: Id, Username: Username, Status: 1, Password: Password})
	}
	return ""
}

func Delete(Id, Password string) string {
	filePath := "client/"+Id+".json"
	fileInfo, err := os.Stat(filePath)

	if fileInfo != nil && err == nil {
		info := ReadSignInfo(filePath)
		truePassword := info.Password
		if truePassword == Password {
			Username := info.Username
			err := os.Remove(filePath)
			if err != nil {
				log.Fatal("Remove file: ", err)
			}
			return LoadSignInfo(SignInfo{Id: Id, Username: Username, Status: 1, Password: Password})
		} else {
			return LoadSignInfo(SignInfo{Status: 0, Errer: "Password is wrong"})
		}
	} else if os.IsNotExist(err) {
		return LoadSignInfo(SignInfo{Status: 0, Errer: "Id is not exist"})
	}
	return ""
}

func WriteTemp(admpsw string, content string) string {
	if admpsw == "65ee5400415cc50cecd95b279b00c475" {
		file, err := os.OpenFile("temp/.tmp", os.O_WRONLY | os.O_APPEND, 0777)
		if err != nil {
			log.Fatal("Write file: ", err)
		} else {
			defer file.Close()
			writer := bufio.NewWriter(file)
			_, err := writer.WriteString("\r\n"+content)
			if err != nil {
				log.Fatal("Write file: ", err)
			} else {
				_ = writer.Flush()
			}
			return LoadSignInfo(SignInfo{Status: 1})
		}
	} else {
		return LoadSignInfo(SignInfo{Status: 0, Errer: "Password is wrong"})
	}
	return ""
}

func Serve(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseForm()
		command := r.Form["command"][0]
		switch command {
			case "signin":
				data := Signin(r.Form["id"][0], r.Form["password"][0])
				fmt.Fprintf(w, data)
			case "signup":
				data := Signup(r.Form["username"][0], r.Form["password"][0])
				fmt.Fprintf(w, data)
			case "delete":
				data := Delete(r.Form["id"][0], r.Form["password"][0])
				fmt.Fprintf(w, data)
			case "writetemp":
				data := WriteTemp(r.Form["admpsw"][0], r.Form["content"][0])
				fmt.Fprintf(w, data)
			default:
				data := ""
				fmt.Fprintf(w, data)
				w.WriteHeader(400)
		}
	} else {
		w.WriteHeader(405)
	}
}

func main() {
	http.HandleFunc("/", Serve)
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("While serving: ", err)
	}
}